package com.hyt.it.ogt.kq.service.gov.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.core.base.BaseEntity;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.constant.CommonConstant;
import com.hyt.core.exception.NestedBusinessException;
import com.hyt.core.util.UUIDUtils;
import com.hyt.exception.exception.BusinessLogicException;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.common.exception.GovInvalidRequestException;
import com.hyt.it.ogt.kq.common.gov.constant.CodeEnum;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.common.gov.constant.StringCodeEnum;
import com.hyt.it.ogt.kq.common.gov.constant.TaskExamTypeEnum;
import com.hyt.it.ogt.kq.common.gov.enums.SubjectImportExamTypeEnums;
import com.hyt.it.ogt.kq.common.gov.utils.XmlUtil;
import com.hyt.it.ogt.kq.common.utils.CharUtil;
import com.hyt.it.ogt.kq.service.gov.feign.ks.KsClient;
import com.hyt.it.ogt.kq.service.gov.feign.ks.model.PushKsSubjectParam;
import com.hyt.it.ogt.kq.service.gov.feign.ks.model.PushTimeSubjectParam;
import com.hyt.it.ogt.kq.service.gov.feign.pt.GovPtClient;
import com.hyt.it.ogt.kq.service.gov.mapper.CandidateSubjectMapper;
import com.hyt.it.ogt.kq.service.gov.mapper.SubjectMapper;
import com.hyt.it.ogt.kq.service.gov.mapper.TimeMapper;
import com.hyt.it.ogt.kq.service.gov.mapper.TimeSubjectMapper;
import com.hyt.it.ogt.kq.service.gov.model.TaskSubjectImportDTO;
import com.hyt.it.ogt.kq.service.gov.model.dto.ExamSubjectDTO;
import com.hyt.it.ogt.kq.service.gov.model.dto.ProgressResult;
import com.hyt.it.ogt.kq.service.gov.model.dto.TaskTimeSubjectArrangeDTO;
import com.hyt.it.ogt.kq.service.gov.model.dto.TimeSubjectBindingDTO;
import com.hyt.it.ogt.kq.service.gov.model.entity.*;
import com.hyt.it.ogt.kq.service.gov.model.excel.*;
import com.hyt.it.ogt.kq.service.gov.model.excel.listener.SubjectListener;
import com.hyt.it.ogt.kq.service.gov.model.param.ExamSubjectParam;
import com.hyt.it.ogt.kq.service.gov.model.param.SubjectParam;
import com.hyt.it.ogt.kq.service.gov.model.vo.ExamRoomTypeVo;
import com.hyt.it.ogt.kq.service.gov.model.vo.TaskTimeSubjectArrangeVO;
import com.hyt.it.ogt.kq.service.gov.roomdata.model.oeds.ExamSubject;
import com.hyt.it.ogt.kq.service.gov.roomdata.model.oeds.OedsSubject;
import com.hyt.it.ogt.kq.service.gov.service.*;
import com.hyt.it.ogt.kq.service.model.entity.Candidate;
import com.hyt.it.ogt.kq.service.model.entity.Subject;
import com.hyt.loginfo.model.Organization;
import com.hyt.loginfo.model.User;
import com.hyt.loginfo.model.UserOrgAccessDTO;
import com.hyt.loginfo.service.IUaDeptAccessService;
import com.hyt.loginfo.service.IUaDeptService;
import com.hyt.model.PageParam;
import com.hyt.progress.service.ProgressManager;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 科目信息表 服务实现类
 * </p>
 *
 * @author huangyh
 * @since 2021-03-08
 */
@Service
public class SubjectServiceImpl extends BaseServiceImpl<SubjectMapper, Subject> implements ISubjectService {

    @Resource
    private CandidateSubjectMapper candidateSubjectMapper;

    @Resource
    private ITimeSubjectService iTimeSubjectService;

    @Resource
    private ITaskService iTaskService;

    @Resource
    private IUaDeptService iUaDeptService;

    @Resource
    private GovPtClient govPtClient;

    @Resource
    private TimeMapper timeMapper;

    @Resource
    private TimeSubjectMapper timeSubjectMapper;

    @Resource
    private SubjectMapper subjectMapper;

    @Resource
    private IUaDeptAccessService iUaDeptAccessService;

    @Resource
    private ITaskRoomService iTaskRoomService;

    @Resource
    private IOfficeAreaService iOfficeAreaService;

    @Resource
    private KsClient ksClient;

    @Override
    public List<Subject> getSubjectByTaskId(String taskId) {
        QueryWrapper<Subject> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(Subject::getTaskId, taskId)
                .eq(Subject::getDelFlag, false)
                .orderByAsc(Subject::getCreateDate);
        return list(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SubjectParam subjectParam, User user) throws KqException {
        // 校验任务数据锁定状态(后续版本考虑优化为从缓存中获取状态)
        iTaskService.isLockDataThrowException(subjectParam.getTaskId());

        //如果任务绑定报名，则不允许添加科目
        Integer type = iTaskService.taskDataType(subjectParam.getTaskId());
        if (type.equals(CodeEnum.TASK_DATA_TYPE_BM.getCode())) {
            throw new KqException(ResponseCode.SUBJECT_ADD_NONE_BM.getCode(),ResponseCode.SUBJECT_ADD_NONE_BM.getMsg());
        }

        //组装科目数据
        Subject subject = new Subject();
        subject.setTaskId(subjectParam.getTaskId())
                .setName(subjectParam.getName())
                .setCode(subjectParam.getCode())
                .setLength(StringUtils.isNotBlank(subjectParam.getLength()) ? NumberUtil.toBigDecimal(subjectParam.getLength()) : null)
                .setHandInTime(StringUtils.isNotBlank(subjectParam.getHandInTime()) ? NumberUtil.toBigDecimal(subjectParam.getHandInTime()) : null)
                .setRemindTime(StringUtils.isNotBlank(subjectParam.getRemindTime()) ? NumberUtil.toBigDecimal(subjectParam.getRemindTime()) : null);
        subject.setOfficeId(user.getOfficeid());
       /* if(Objects.isNull(subjectParam.getDeptId())){
            subject.setDeptId(user.getOrganizationid());
        } else {
            subject.setDeptId(subjectParam.getDeptId());
        }*/
        subject.setDeptId(subjectParam.getDeptId());
        subject.setGrade(subjectParam.getGrade());
        subject.setRoomTypeId(subjectParam.getRoomTypeId());
        subject.setGrandDesc(subjectParam.getGrandDesc());
        subject.setRoomTypeName(subjectParam.getRoomTypeName());
        subject.setId(UUIDUtils.newSortUUID());
        //科目参数重复性校验
        this.checkSubjectRepeat(subject);
        //科目参数合理性校验
        this.checkSubjectRationality(subject);
        //插入科目表
        if (!save(subject)) {
            throw new KqException(ResponseCode.SUBJECT_ADD_EXCEPTION.getCode(),
                    ResponseCode.SUBJECT_ADD_EXCEPTION.getMsg());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Subject subject) throws GovInvalidRequestException {


        //科目参数重复性校验
        this.checkSubjectRepeat(subject);
        //科目参数合理性校验
        this.checkSubjectRationality(subject);
        //更新科目表
        if (!updateById(subject)) {
            throw new NestedBusinessException("更新科目表失败");
        }
        if(Objects.isNull(subject.getDeptId())){
            LambdaUpdateWrapper<Subject> updateC = Wrappers.lambdaUpdate();
            updateC.eq(Subject::getId,subject.getId());
            updateC.set(Subject::getDeptId,null);
            if(!this.update(updateC)){
                throw new NestedBusinessException("更新科目表失败");
            }
        }
    }

    @Override
    public Subject query(String subjectId) {
        QueryWrapper<Subject> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(Subject::getId, subjectId)
                .eq(Subject::getDelFlag, false);
        Subject one = getOne(queryWrapper);
        if(Objects.nonNull(one)){
            if(Objects.nonNull(one.getRoomTypeId())){
                List<ExamRoomTypeVo> types = this.queryExamRoomTYpes();
                //转成map
                Map<String,ExamRoomTypeVo> typeMap = types.stream()
                        .collect(Collectors.toMap(ExamRoomTypeVo::getId,Function.identity(),(k1,k2) -> k1));
                String typeName = typeMap.get(one.getRoomTypeId()) == null ? "" : typeMap.get(one.getRoomTypeId()).getTypeName();
                one.setRoomTypeName(typeName);
            }
            if(Objects.nonNull(one.getDeptId())){
                List<String> deptIds = new ArrayList<>();
                deptIds.add(one.getDeptId());
                Map<String, String> ancestorsNames = iUaDeptService.getAncestorsNames(deptIds);
                String deptName = ancestorsNames.get(one.getDeptId()) == null ? "" : ancestorsNames.get(one.getDeptId());
                one.setDeptName(deptName);
            }
        }
        return one;
    }

    @Override
    public Subject queryByBmStudentId(String taskId, String bmSubjectId) {
        Subject subject = this.lambdaQuery()
                .eq(Subject::getTaskId, taskId)
                .eq(Subject::getBmSubjectId, bmSubjectId)
                .eq(Subject::getDelFlag, false)
                .last("LIMIT 1")
                .one();
        return subject;
    }

    @Override
    @Transactional(rollbackFor = NestedBusinessException.class)
    public void delete(String subjectIds) {

        List<String> subjectIdList = Arrays.asList(subjectIds.split(","));
        subjectIdList.stream().forEach(subjectId -> {
            Integer count = iTimeSubjectService.lambdaQuery()
                    .eq(TimeSubject::getSubjectId,subjectId)
                    .eq(TimeSubject::getDelFlag,false).count();
            //在没有绑定批次的情况下，下来允许删除
            if (count == 0) {
                this.lambdaUpdate()
                        .eq(Subject::getId,subjectId)
                        .eq(Subject::getDelFlag,false)
                        .set(Subject::getDelFlag,true)
                        .update();
            }
        });


/*
        //删除科目表
        LambdaUpdateWrapper<Subject> subjectLambdaUpdateWrapper = Wrappers.lambdaUpdate();
        subjectLambdaUpdateWrapper.in(Subject::getId,subjectIdList)
                .set(Subject::getDelFlag,true);
        this.update(subjectLambdaUpdateWrapper);*/
//        this.deleteSubjectByIds(subjectIdList);
        //删除考生科目表
        //this.deleteCandidateSubject(subjectIdList);
    }

    /**
     * 删除考生科目表
     * @param subjectIdList 科目id
     * @throws NestedBusinessException 删除失败，抛出异常
     */
    private void deleteCandidateSubject(List<String> subjectIdList) throws NestedBusinessException {
        if (!candidateSubjectMapper.deleteByIds(subjectIdList)) {
            throw new NestedBusinessException("删除考生科目表失败");
        }
    }

    /**
     * 根据科目id删除科目
     * @param subjectIdList 科目id的List
     * @throws NestedBusinessException 删除失败，抛出异常
     */
    private void deleteSubjectByIds(List<String> subjectIdList) throws NestedBusinessException {
        if (!removeByIds(subjectIdList)) {
            throw new NestedBusinessException("删除科目表失败");
        }
    }

    /**
     * 科目参数合理性校验
     * @param subject 科目参数
     * @throws KqException 参数校验不通过，抛出异常
     */
    private void checkSubjectRationality(Subject subject) throws KqException {
        BigDecimal length = subject.getLength();
        BigDecimal handInTime = subject.getHandInTime();
        BigDecimal remindTime = subject.getRemindTime();
        String examType = iTaskService.getExamType(subject.getTaskId());
        if (TaskExamTypeEnum.OFFLINE.getCode().equals(examType)) {
            //线下机考，有科目时间
            if (ObjectUtils.isEmpty(length)) {
                //考试时长不能为空
                throw new KqException(ResponseCode.SUBJECT_LENGTH_CAN_NOT_BE_EMPTY.getCode(),
                        ResponseCode.SUBJECT_LENGTH_CAN_NOT_BE_EMPTY.getMsg());
            }
            if (ObjectUtils.isEmpty(handInTime)) {
                //开考后允许交卷分钟数不能为空
                throw new KqException(ResponseCode.SUBJECT_HAND_IN_TIME_CAN_NOT_BE_EMPTY.getCode(),
                        ResponseCode.SUBJECT_HAND_IN_TIME_CAN_NOT_BE_EMPTY.getMsg());
            }
            if (ObjectUtils.isEmpty(remindTime)) {
                //结束前提醒交卷分钟数不能为空
                throw new KqException(ResponseCode.SUBJECT_REMIND_TIME_CAN_NOT_BE_EMPTY.getCode(),
                        ResponseCode.SUBJECT_REMIND_TIME_CAN_NOT_BE_EMPTY.getMsg());
            }
        }
//        if (!MathUtil.isPositiveInteger(length)) {
//            //科目时长必须为正整数
//            throw new InvalidRequestException(ResponseCode.SUBJECT_SECOND_FORMAT_INVALID.getCode(), ResponseCode.SUBJECT_SECOND_FORMAT_INVALID.getMsg());
//        }
//        if (!MathUtil.isNonNegativeInteger(handInTime)) {
//            //开考后允许交卷时间必须为非负整数
//            throw new InvalidRequestException(ResponseCode.TASK_START_COMMIT_PAPER_SECOND_FORMAT_INVALID.getCode(), ResponseCode.TASK_START_COMMIT_PAPER_SECOND_FORMAT_INVALID.getMsg());
//
//        }
//        if (length.compareTo(handInTime) < 0) {
//            //开考后允许交卷时间必须小于或等于科目时长
//            throw new InvalidRequestException(ResponseCode.TASK_START_ALLOW_COMMIT_SECOND_INVALID.getCode(),ResponseCode.TASK_START_ALLOW_COMMIT_SECOND_INVALID.getMsg());
//        }
//        if (length.compareTo(remindTime) < 0) {
//            //结束前提醒交卷时间必须小于或等于科目时长
//            throw new InvalidRequestException(ResponseCode.TASK_END_ALLOW_PAPER_COMMIT_SECOND_INVALID.getCode(), ResponseCode.TASK_END_ALLOW_PAPER_COMMIT_SECOND_INVALID.getMsg());
//
//        }
    }

    /**
     * 科目参数重复性校验
     * @param subject 科目参数
     * @throws KqException 参数校验不通过，抛出异常
     */
    @Override
    public void checkSubjectRepeat(Subject subject) throws KqException {
        //获取已有科目
        String taskId = subject.getTaskId();
        List<Subject> subjectList = this.getSubjectByTaskId(taskId);
        if (!CollectionUtils.isEmpty(subjectList)) {
            String code = subject.getCode();
            String name = subject.getName();
            for (Subject s : subjectList) {
                //更新时不校验自己
                if(null != subject.getId() && subject.getId().equals(s.getId())){
                    continue;
                }
                //检查科目编号是否重复
                if (Objects.equals(code,s.getCode())) {
                    //科目编号重复
                    throw new GovInvalidRequestException(ResponseCode.SUBJECT_CODE_EXIST.getCode(), ResponseCode.SUBJECT_CODE_EXIST.getMsg());
                }
                //检查科目名称是否重复
                if (name.equals(s.getName())) {
                    //科目名称重复
                    throw new GovInvalidRequestException(ResponseCode.SUBJECT_NAME_EXIST.getCode(), "科目" + s.getName() + ResponseCode.SUBJECT_NAME_EXIST.getMsg());
                }
            }
        }
    }

    @Override
    public Map<String,Subject> getSubjectMapKeyId(String taskId) {

        List<Subject> subjectList = getSubjectByTaskId(taskId);
        Map<String,Subject> map = new HashMap<>(subjectList.size());
        subjectList.stream().forEach(subject -> {
            map.put(subject.getId(),subject);
        });

        return map;
    }

    @Override
    public List<Subject> getIdCode(String taskId) {
        QueryWrapper<Subject> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .select(Subject::getId, Subject::getCode)
                .eq(Subject::getTaskId, taskId)
                .eq(Subject::getDelFlag, false)
                .orderByAsc(Subject::getCode);
        return list(queryWrapper);
    }

    @Override
    public void deleteByTaskId(String taskId) {
        this.lambdaUpdate()
                .eq(Subject::getTaskId, taskId)
                .eq(Subject::getDelFlag, false)
                .set(Subject::getDelFlag, true)
                .update();
    }

    @Override
    public boolean hasSubject(String taskId, String subjectId) {
        return this.lambdaQuery().select(Subject::getId)
                .eq(Subject::getTaskId, taskId)
                .eq(Subject::getId, subjectId)
                .eq(Subject::getDelFlag, false)
                .last("LIMIT 1")
                .oneOpt()
                .isPresent();
    }

    @Override
    public List<Subject> listByCodes(String taskId, Collection<?> subjectCodes) {
        return this.lambdaQuery()
                .eq(Subject::getTaskId, taskId)
                .in(!CollectionUtils.isEmpty(subjectCodes), Subject::getCode, subjectCodes)
                .eq(Subject::getDelFlag, false)
                .list();
    }

    @Override
    public Subject getByTimeSubjectId(String timeSubjectId) {
        return baseMapper.getByTimeSubjectId(timeSubjectId);
    }

    @Override
    public Integer countByTaskId(String taskId) {
        return this.lambdaQuery()
                .eq(Subject::getTaskId, taskId)
                .eq(Subject::getDelFlag, Boolean.FALSE)
                .count();
    }

    /**
     * 查询批次选择的科目
     * @param param
     * @return
     */
    @Override
    public List<TaskTimeSubjectArrangeVO> taskTimeSubjectArrange(TaskTimeSubjectArrangeDTO param){
        //搜索已经选择的科目
        if(Objects.equals("1",param.getQueryType())){
            List<TaskTimeSubjectArrangeVO> vos = this.baseMapper.taskTimeSubjectArrange(param);
            if(!CollectionUtils.isEmpty(vos)){
                //处理机构数据
                List<String> deptIds = vos.stream()
                        .filter(e -> StringUtils.isNotBlank(e.getDeptId())).map(TaskTimeSubjectArrangeVO::getDeptId).collect(Collectors.toList());
                Map<String, String> ancestorsNames = new HashMap<>();
                if(!CollectionUtils.isEmpty(deptIds)){
                    ancestorsNames = iUaDeptService.getAncestorsNames(deptIds);
                }
                //用与处理是否选中
                LambdaQueryWrapper<TimeSubject> tsQuery = Wrappers.lambdaQuery();
                tsQuery.eq(TimeSubject::getTimeId,param.getTimeId()).eq(TimeSubject::getTaskId,param.getTaskId());
                tsQuery.eq(TimeSubject::getDelFlag,Boolean.FALSE);
                List<TimeSubject> timeSubjects = iTimeSubjectService.getBaseMapper().selectList(tsQuery);
                List<String> subjectIds = timeSubjects.stream().map(TimeSubject::getSubjectId).collect(Collectors.toList());

                //处理考场类型
                List<ExamRoomTypeVo> types = this.queryExamRoomTYpes();
                //转成map
                Map<String,ExamRoomTypeVo> typeMap = types.stream()
                        .collect(Collectors.toMap(ExamRoomTypeVo::getId,Function.identity(),(k1,k2) -> k1));

                for(TaskTimeSubjectArrangeVO v : vos){
                    String deptName = StringUtils.isNotBlank(ancestorsNames.get(v.getDeptId())) ? ancestorsNames.get(v.getDeptId()) : null;
                    v.setDeptName(deptName);
                    //存在就是选中了的
                    if(subjectIds.contains(v.getSubjectId())){
                        v.setSelected(Boolean.TRUE);
                    } else {
                        v.setSelected(Boolean.FALSE);
                    }
                    v.setRoomTypeName(Objects.nonNull(typeMap.get(v.getRoomTypeId())) ? typeMap.get(v.getRoomTypeId()).getTypeName() : "");
                }
            }
            return vos;
        }
        //查没有选择的
        List<TaskTimeSubjectArrangeVO> vos = this.baseMapper.taskTimeSubjectArrangeNotSelected(param);
        if(!CollectionUtils.isEmpty(vos)){
            //处理机构数据
            List<String> deptIds = vos.stream()
                    .filter(e -> StringUtils.isNotBlank(e.getDeptId())).map(TaskTimeSubjectArrangeVO::getDeptId).collect(Collectors.toList());
            Map<String, String> ancestorsNames = new HashMap<>();
            if(!CollectionUtils.isEmpty(deptIds)){
                ancestorsNames = iUaDeptService.getAncestorsNames(deptIds);
            }
            for(TaskTimeSubjectArrangeVO v : vos){
                String deptName = StringUtils.isNotBlank(ancestorsNames.get(v.getDeptId())) ? ancestorsNames.get(v.getDeptId()) : null;
                v.setDeptName(deptName);
            }
        }
        return vos;
    }

    //获取区域全称
    private String getAreaFullName(String areaId){
        ApiResponse<Object> response = govPtClient.joinAreaAddress(areaId);
        if(Objects.isNull(response) || !Objects.equals(ResponseCode.SUCCESS.getCode(),response.getCode())){
            throw new KqException();
        }
        return String.valueOf(response.getData());
    }


    /**
     * 批次绑定科目
     *
     * @param param
     * @param user
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean bingTimeSubject(TimeSubjectBindingDTO param, User user){
        String taskId = param.getTaskId();
        String timeId = param.getTimeId();
        List<String> subjectIds = param.getSubjectIds();
        //先查任务情况
        Task task = iTaskService.getTaskById(taskId);
        //校验数据锁定
        if (task.getDataLock()) {
            throw new KqException(ResponseCode.TASK_DATA_LOCK_TRUE.getCode(),"数据已锁定，不允许操作此功能。");
        }
        switch (TaskExamTypeEnum.getByCode(task.getExamType())) {
            //线上编排参数校验
            case ONLINE:
                this.validOnlineTimeSubject(subjectIds, task,timeId);
                break;
            //线下编排参数校验
            case OFFLINE:
                break;
        }
        Time time = timeMapper.selectById(timeId);
        if(Objects.isNull(time)){
            throw new KqException(ResponseCode.TIMES_SUBJECT_BINDING_PARAM.getCode(),"入参中批次ID不存在记录");
        }
        //判断批次是更新还是保存
        //1：如果为空刚是全部清理
        LambdaUpdateWrapper<TimeSubject> update = Wrappers.lambdaUpdate();
        update.eq(TimeSubject::getTaskId,taskId).eq(TimeSubject::getTimeId,timeId);
        update.set(TimeSubject::getDelFlag,Boolean.TRUE);
        timeSubjectMapper.update(null,update);
        if(CollectionUtils.isEmpty(subjectIds)){
            //推送批次给考试
            PushTimeSubjectParam subjectParam = new PushTimeSubjectParam();
            subjectParam.setTimeId(timeId);
            subjectParam.setTaskId(taskId);
            //subjectParam.setOfficeId(user.getOfficeid());
            //subjectParam.setDeptId(user.getOrganizationid());
            ApiResponse<Object> response = ksClient.pushTimeSubject(subjectParam);
            if(!Objects.equals(ResponseCode.SUCCESS.getCode(),response.getCode())){
                throw new KqException(ResponseCode.PUSH_TIME_SUBJECT_ERROR);
            }
            return Boolean.TRUE;
        }
        //用与收集批次科目关联
        List<TimeSubject> timeSubjects = new ArrayList<>(subjectIds.size());
        List<PushKsSubjectParam> subjects = new ArrayList<>(subjectIds.size());
        for(String subjectId : subjectIds){
            //判断一下科目是否真的存在
            Subject subject = subjectMapper.selectById(subjectId);
            if(Objects.isNull(subject)){
                throw new KqException(ResponseCode.TIMES_SUBJECT_BINDING_PARAM.getCode(),"入参中" + subjectId + "科目ID不存在记录");
            }
            TimeSubject timeSubject = new TimeSubject();
            timeSubject.setDelFlag(Boolean.FALSE);
            timeSubject.setCreateDate(LocalDateTime.now());
            timeSubject.setUpdateDate(LocalDateTime.now());
            timeSubject.setSubjectId(subjectId);
            timeSubject.setTimeId(timeId);
            timeSubject.setTaskId(taskId);
            timeSubject.setId(UUIDUtils.newSortUUID());
            timeSubjects.add(timeSubject);

            PushKsSubjectParam pushSubject = new PushKsSubjectParam();
            pushSubject.setSubjectName(subject.getName());
            if(Objects.nonNull(subject.getBmSubjectId())){
                pushSubject.setSubjectId(subject.getBmSubjectId());
            } else {
                pushSubject.setSubjectId(subject.getId());
            }
            pushSubject.setOfficeId(subject.getOfficeId());
            pushSubject.setDeptId(subject.getDeptId());
            subjects.add(pushSubject);
        }
        if(!CollectionUtils.isEmpty(timeSubjects)){
            iTimeSubjectService.saveBatch(timeSubjects);
            //推送批次给考试
            PushTimeSubjectParam subjectParam = new PushTimeSubjectParam();
            subjectParam.setTimeId(timeId);
            subjectParam.setTaskId(taskId);
            subjectParam.setSubjects(subjects);
            ApiResponse<Object> response = ksClient.pushTimeSubject(subjectParam);
            if(!Objects.equals(ResponseCode.SUCCESS.getCode(),response.getCode())){
                throw new KqException(ResponseCode.PUSH_TIME_SUBJECT_ERROR);
            }
        }
        return Boolean.TRUE;
    }

    /**
     * 线上模式，校验批次科目，一个科目只能存在于一个批次中。
     * @param subjectIds
     */
    private void validOnlineTimeSubject(List<String> subjectIds, Task task,String timeId) {

        //1。一个科目不允许存在于多个批次
        for (String subjectId : subjectIds){
            Boolean flag = iTimeSubjectService.existTimeSubject(task.getId(),subjectId,timeId);
            if (flag) {
                throw new KqException(ResponseCode.TIMES_ONLINE_TIME_SUBJECT_EXIST.getCode(),
                        ResponseCode.TIMES_ONLINE_TIME_SUBJECT_EXIST.getMsg());
            }
        }
    }

    /**
     * 导入机构平台科目
     *
     * @param param
     * @param user
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importPt(TaskSubjectImportDTO param, User user){
        iTaskService.isLockDataThrowException(param.getTaskId());
        //如果任务绑定报名，则不允许添加科目 //todo 修改成前端只传ids
        Integer type = iTaskService.taskDataType(param.getTaskId());
        if (type.equals(CodeEnum.TASK_DATA_TYPE_BM.getCode())) {
            throw new KqException(ResponseCode.SUBJECT_ADD_NONE_BM.getCode(),ResponseCode.SUBJECT_ADD_NONE_BM.getMsg());
        }
        //List<ExamSubjectDTO> subjects = param.getExamSubjectDTOS();
        //取出id
        //List<String> subjectIds = subjects.stream().map(ExamSubjectDTO::getId).collect(Collectors.toList());
        List<String> subjectIds = param.getExamSubjectDTOS();
        if(CollectionUtils.isEmpty(subjectIds)){
            return;
        }
        ApiResponse<List<ExamSubjectDTO>> response = govPtClient.listAll(subjectIds);
        if(Objects.isNull(response) || !Objects.equals(ResponseCode.SUCCESS.getCode(),response.getCode()) ||
                Objects.isNull(response.getData())){
            throw new KqException(ResponseCode.SUBJECT_IMPORT_FROM_PT);
        }
        List<ExamSubjectDTO>  subjects = response.getData();
        List<Subject> entitys = new ArrayList<>(subjects.size());
        Integer code = getLastTimeRoomCode(param.getTaskId());
        for (ExamSubjectDTO s : subjects){
            //组装科目数据
            Subject subject = new Subject();
            subject.setTaskId(param.getTaskId())
                    .setName(s.getSubjectName())
                    .setCode(s.getCode())
                    .setLength(StringUtils.isNotBlank(s.getLength()) ? NumberUtil.toBigDecimal(s.getLength()) : null)
                    .setHandInTime(StringUtils.isNotBlank(s.getHandInTime()) ? NumberUtil.toBigDecimal(s.getHandInTime()) : null)
                    .setRemindTime(StringUtils.isNotBlank(s.getRemindTime()) ? NumberUtil.toBigDecimal(s.getRemindTime()) : null);
            subject.setOfficeId(s.getOfficeId());
            subject.setDeptId(s.getDeptId());
            subject.setGrade(s.getGrade());
            subject.setRoomTypeId(s.getRoomTypeId());
            subject.setGrandDesc(s.getGrandDesc());
            subject.setRoomTypeName(s.getRoomTypeName());
            subject.setId(UUIDUtils.newSortUUID());
            subject.setBmSubjectId(s.getId());
            if(StringUtils.isBlank(subject.getCode())){
                //按产品需求  前边要拼接km字符串，当我们去数据库取上次最后的数值后，做拼接 km001 km100 km099这种格式接接
                subject.setCode(String.valueOf(code));
                code += 1;
            }
            //科目参数重复性校验
            this.checkSubjectRepeat(subject);
            //科目参数合理性校验
            this.checkSubjectRationality(subject);
            entitys.add(subject);
        }
        if(!CollectionUtils.isEmpty(entitys)){
            saveBatch(entitys);
        }
    }


    /**
     * 获取当前最大科目编号
     * @param taskId 考试任务id
     * @return 当前最大科目编号
     */
    public int getLastTimeRoomCode(String taskId) {
        /*
        QueryWrapper<Subject> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .select(Subject::getCode)
                .eq(Subject::getTaskId, taskId)
                .eq(Subject::getDelFlag, false)
                .last("ORDER BY CAST(code AS SIGNED) DESC LIMIT 1");
        //.last("ORDER BY TRIM(LEADING 'km' FROM `code` ) DESC LIMIT 1");
        Subject timeRoom = getOne(queryWrapper);
        String code = Optional.ofNullable(timeRoom)
                .map(Subject::getCode)
                .orElse("0");*/
        long time = System.currentTimeMillis();
        long milliSeconds = time % 1000000l;
        int number = (int) Math.floor(milliSeconds);
        /*
        if(!NumberUtils.isDigits(code)){
            code = code.substring(2);
        }*/
        return number;
    }

    /**
     * 从平台获取考场类型表表
     * @param user
     * @return
     */
    @Override
    public List<ExamRoomTypeVo> queryExamRoomTYpes(){
        ApiResponse<Object> response = govPtClient.listAll();
        if (Objects.isNull(response) || !Objects.equals(ResponseCode.SUCCESS.getCode(),response.getCode())){
            throw new KqException(ResponseCode.REGISTERED_SUBJECT_TEMPLATE_EXAM_TYPE.getCode(),ResponseCode.REGISTERED_SUBJECT_TEMPLATE_EXAM_TYPE.getMsg());
        }
        List<ExamRoomTypeVo> vos = JSON.parseArray(JSON.toJSONString(response.getData()), ExamRoomTypeVo.class);
        return vos;
    }

    /**
     * 获取部门权限部门列表
     * @param user
     * @return
     */
    @Override
    public UserOrgAccessDTO getAccessOrgsByUserId(User user){
        return iUaDeptAccessService.getUserAccessDeptIds(user.getId());
    }

    /**
     * 当前用户所在机构的所有组织层级，不限制当前用户的层级
     * @return
     */
    @Override
    public Map<String, Organization> getOfficeAllDepts(){
        List<Organization> organizations = iUaDeptService.getOfficeAllDepts();
        Map<String,Organization> orgMap = organizations.stream().collect(Collectors.toMap(Organization::getId,Function.identity(),(k1,k2) -> k1));
        return orgMap;
    }

    /**
     * 获取任务区域信息
     * @return
     */
    public List<OfficeAreaSheet> getOfficeAreaSheet(){
        List<OfficeAreaSheet> officeAreaSheets = new ArrayList<>();
        // 二级
        List<TaskArea> districtList = new ArrayList<>();
        // 三级
        Map<String, TaskArea> dictionaryMap = new HashMap<>(3);
        List<TaskArea> allAreas = iOfficeAreaService.getAllAreaList();
        // 得到字典,和县级的数据
        for (TaskArea taskArea : allAreas){
            if(3 == taskArea.getRegionLevel()) {
                districtList.add(taskArea);
            }
            dictionaryMap.put(taskArea.getAreaId(), taskArea);
        }
        // 组装数据
        for(TaskArea taskArea : districtList){
            OfficeAreaSheet officeAreaSheet = new OfficeAreaSheet();
            officeAreaSheet.setDistrictCode(taskArea.getAreaId());
            officeAreaSheet.setDistrictName(taskArea.getName());
            TaskArea cityData = dictionaryMap.get(taskArea.getParentId());
            if(null != cityData){
                officeAreaSheet.setCityCode(cityData.getAreaId());
                officeAreaSheet.setCityName(cityData.getName());
                TaskArea provinceData = dictionaryMap.get(cityData.getParentId());
                if(null != provinceData) {
                    officeAreaSheet.setProvinceCode(provinceData.getAreaId());
                    officeAreaSheet.setProvinceName(provinceData.getName());
                }
            }
            officeAreaSheets.add(officeAreaSheet);
        }
        // 返回数据
        return officeAreaSheets;
    }

    //获取平台的区域map key = id value = object
    public Map<String,TaskArea> getAllAreaMap(){
        List<TaskArea> allAreas = iOfficeAreaService.getAllAreaList();
        Map<String,TaskArea> map = allAreas.stream().collect(Collectors.toMap(TaskArea::getAreaId,Function.identity(),(k1,k2) -> k1));
        return map;
    }

    /**
     * 导入科目信息
     *
     * @param fileUrl
     * @param taskId
     * @param user
     * @return
     */
    @Override
    public void importSubject(String fileUrl, String taskId, User user) throws Exception{
        String fileSuffix = FileUtil.getSuffix(fileUrl);
        if (!StrUtil.equalsAny(fileSuffix, "xlsx", "xls")) {
            BusinessLogicException.throwException(43191303, "上传的文件类型不匹配");
        }
        File uploadFile = FileUtil.createTempFile(StrPool.DOT + fileSuffix, Boolean.TRUE);
        long fileSize = HttpUtil.downloadFile(fileUrl, uploadFile);
        if (fileSize == CommonConstant.ZERO) {
            BusinessLogicException.throwException(43191302, "请勿上传空文件");
        }
        ProgressManager.updateProgressCurrent(3L, "文件接收成功");
        // 异常信息
        List<ExcelErr> errList = new ArrayList<>();
        //校验excel文件
        this.excelVerify(uploadFile);
        ProgressManager.updateProgressCurrent(5L, "Excel文件格式校验完成");

        List<ImportSubjectSheet> subjectSheets = new ArrayList<>();
        //List<ImportSelfAreaSheet> areaList =  new ArrayList<>();

        // 读取excel
        this.readExcel(uploadFile, subjectSheets);
        if(CollectionUtil.isEmpty(subjectSheets)){
            BusinessLogicException.throwException(43191304, "请勿上传一个空文件");
        }
        ProgressManager.updateProgressCurrent(10L, "Excel文件读取完成");

        List<Subject> subjects = new ArrayList<>();
        Map<String, String> districtMap = new HashMap<>();

        // 一个sheet异常记录
        //ExcelErr sheet3Err = ExcelErr.builder().sheetNo(0).sheetName("区域信息").build();
        //List<TaskArea> selfLevelList = new ArrayList<>();
        //List<ExcelRowErr> row3Errs = iTaskRoomService.analysisSelfLevelExcelData(taskId, districtMap);

        //sheet3Err.setRowErrList(row3Errs);
        //errList.add(sheet3Err);

        // 一个sheet异常记录
        ExcelErr sheet2Err = ExcelErr.builder().sheetNo(0).sheetName("科目信息").build();
        // 解析考点考场sheet
        List<ExcelRowErr> rowErrs = this.analysisExcelData(taskId, subjectSheets, subjects,user);
        ProgressManager.updateProgressCurrent(45L, "Excel文件科目校验完成");
        sheet2Err.setRowErrList(rowErrs);
        errList.add(sheet2Err);
        if(!CollectionUtils.isEmpty(rowErrs)){
            ProgressManager.finish(ProgressResult.builder().success(Boolean.FALSE).result(errList).build());
            return;
        }
        ProgressManager.updateProgressCurrent(65L, "验证没有错误准备入库");
        //没有问题入库
        if(!CollectionUtils.isEmpty(subjects)){
            this.saveBatch(subjects);
        }
        ProgressManager.updateProgressCurrent(99L, "入库完成");
        ProgressManager.finish(ProgressResult.builder().success(Boolean.TRUE).build());
    }

    private List<ExcelRowErr> analysisExcelData(String taskId, List<ImportSubjectSheet> subjectSheets, List<Subject> subjects, User user) {
        List<ExcelRowErr> errList = new ArrayList<>();
        //Map<String, String> subjectNameExcelRepeat = new HashMap<>();
        Map<String, Organization> deptMap = getOfficeOrganizationMap();

        //获取已有科目
        List<Subject> subjectList = this.getSubjectByTaskId(taskId);

        int lastTimeRoomCode = getLastTimeRoomCode(taskId);
        //处理excel表中的重名
        Map<String,List<ImportSubjectSheet>> names = subjectSheets.stream().filter(s -> StringUtils.isNotBlank(s.getSubjectName()))
                .collect(Collectors.toMap(ImportSubjectSheet::getSubjectName,s -> {
                    List<ImportSubjectSheet> list = new ArrayList<>();
                    list.add(s);
                    return list;
                },(oldList, newList) -> {
                    oldList.addAll(newList);
                    return oldList;
                }));
        //处理excel表中的重名
        Map<String,List<ImportSubjectSheet>> codes = subjectSheets.stream().filter(s -> StringUtils.isNotBlank(s.getSubjectCode()))
                .collect(Collectors.toMap(ImportSubjectSheet::getSubjectCode,s -> {
                    List<ImportSubjectSheet> list = new ArrayList<>();
                    list.add(s);
                    return list;
                },(oldList, newList) -> {
                    oldList.addAll(newList);
                    return oldList;
                }));

        //处理数据
        for (int i = 0; i < subjectSheets.size(); i++) {
            ImportSubjectSheet subjectSheet = subjectSheets.get(i);
            // 校验数据
            List<ExcelLineErr> rowErrs = this.checkValue(subjectSheet,deptMap,subjectList,names,codes);
            if(!rowErrs.isEmpty()) {
                errList.add(ExcelRowErr.builder().row(i+1).lineErrList(rowErrs).build());
                continue;
            }
            Organization dept = deptMap.get(subjectSheet.getMinDept());
            Subject subject = new Subject();
            subject.setId(subjectSheet.getId());
            subject.setName(subjectSheet.getSubjectName());
            if(Objects.nonNull(dept)){
                subject.setOfficeId(dept.getOfficeid());
                subject.setDeptId(dept.getId());
            }
            subject.setDelFlag(Boolean.FALSE);
            subject.setTaskId(taskId);
            subject.setCreateBy(user.getId());
            subject.setUpdateBy(user.getId());
            Optional<SubjectImportExamTypeEnums> byCode =
                    SubjectImportExamTypeEnums.getByCode(NumberUtils.toInt(subjectSheet.getExamType(), 0));
            if(byCode.isPresent()){
                subject.setRoomTypeId(byCode.get().getId());
                subject.setRoomTypeName(byCode.get().getDesc());
            }
            if (StrUtil.isNotBlank(subjectSheet.getSubjectCode())){
                subject.setCode(subjectSheet.getSubjectCode());
            } else {
                lastTimeRoomCode = lastTimeRoomCode + 1;
                subject.setCode(lastTimeRoomCode+"");
            }
            subjects.add(subject);
        }
        return errList;
    }

    /**
     * 科目参数重复性校验
     * @param subject 科目参数
     * @throws KqException 参数校验不通过，抛出异常
     */
    private String checkSubjectNameRepect(List<Subject> subjectList,ImportSubjectSheet subject) throws KqException {
        String errorMsg = null;
        if (!CollectionUtils.isEmpty(subjectList)) {
            String name = subject.getSubjectName();
            for (Subject s : subjectList) {
                //更新时不校验自己
                if(Objects.nonNull(subject.getId()) && Objects.equals(subject.getId(),s.getId())){
                    continue;
                }
                //检查科目名称是否重复
                if (name.equals(s.getName())) {
                    //科目名称重复
                    //throw new GovInvalidRequestException(ResponseCode.SUBJECT_NAME_EXIST.getCode(), "科目" + s.getName() + ResponseCode.SUBJECT_NAME_EXIST.getMsg());
                    errorMsg = "科目:" + s.getName() + "名称重复";
                    return errorMsg;
                }
            }
        }
        return errorMsg;
    }

    /**
     * 科目参数重复性校验
     * @param subject 科目参数
     * @throws KqException 参数校验不通过，抛出异常
     */
    private String checkSubjectCodeRepect(List<Subject> subjectList,ImportSubjectSheet subject) throws KqException {
        String errorMsg = null;
        if (!CollectionUtils.isEmpty(subjectList)) {
            String code = subject.getSubjectCode();
            for (Subject s : subjectList) {
                //更新时不校验自己
                if(Objects.nonNull(subject.getId()) && Objects.equals(subject.getId(),s.getId())){
                    continue;
                }
                //检查科目名称是否重复
                if (code.equals(s.getCode())) {
                    //科目名称重复
                    //throw new GovInvalidRequestException(ResponseCode.SUBJECT_NAME_EXIST.getCode(), "科目" + s.getName() + ResponseCode.SUBJECT_NAME_EXIST.getMsg());
                    errorMsg = "科目代码:" + s.getCode() + "重复";
                    return errorMsg;
                }
            }
        }
        return errorMsg;
    }

    //检查单表数据
    private List<ExcelLineErr> checkValue(ImportSubjectSheet subjectSheet, Map<String, Organization> deptMap, List<Subject> subjectList,
                                          Map<String, List<ImportSubjectSheet>> names,Map<String, List<ImportSubjectSheet>> codes) {
        List<ExcelLineErr> rowErrs = new ArrayList<>();
        if(StringUtils.isBlank(subjectSheet.getSubjectName())){
            rowErrs.add(ExcelLineErr.builder().line(1).msg("科目名称为空").build());
        } else {
            //判断是否有超过长度的
            int chineseLength = CharUtil.getChineseLength(subjectSheet.getSubjectName());
            int notChineseLength = CharUtil.getNotChineseLength(subjectSheet.getSubjectName());
            if(chineseLength > 20 || notChineseLength > 60 || subjectSheet.getSubjectName().length() > 60){
                rowErrs.add(ExcelLineErr.builder().line(1).msg(subjectSheet.getSubjectName() + " 名称不能超过20个汉字或60个字符").build());
            } else {
                //判断是否有重名的
                String errorMsg = checkSubjectNameRepect(subjectList,subjectSheet);
                if(StringUtils.isNotBlank(errorMsg)){
                    rowErrs.add(ExcelLineErr.builder().line(1).msg(errorMsg).build());
                } else {
                    List<ImportSubjectSheet> sheets = names.get(subjectSheet.getSubjectName());
                    if(!CollectionUtils.isEmpty(sheets) && sheets.size() > 1){
                        //科目名称重复
                        errorMsg = "科目:" + subjectSheet.getSubjectName() + "名称重复";
                        rowErrs.add(ExcelLineErr.builder().line(1).msg(errorMsg).build());
                    }
                }
            }
        }

        if(StringUtils.isNotBlank(subjectSheet.getSubjectCode())){
            //判断是否有超过长度的
            int chineseLength = CharUtil.getChineseLength(subjectSheet.getSubjectCode());
            if (chineseLength > 0)  {
                rowErrs.add(ExcelLineErr.builder().line(1).msg(subjectSheet.getSubjectCode() + " 科目代码不能包含中文").build());
            }

            //判断是否有重名的
            String errorMsg = checkSubjectCodeRepect(subjectList,subjectSheet);
            if(StringUtils.isNotBlank(errorMsg)){
                rowErrs.add(ExcelLineErr.builder().line(1).msg(errorMsg).build());
            } else {
                List<ImportSubjectSheet> sheets = codes.get(subjectSheet.getSubjectName());
                if(!CollectionUtils.isEmpty(sheets) && sheets.size() > 1){
                    //科目名称重复
                    errorMsg = "科目代码:" + subjectSheet.getSubjectName() + "名称重复";
                    rowErrs.add(ExcelLineErr.builder().line(1).msg(errorMsg).build());
                }
            }

        }

        if(StringUtils.isNotBlank(subjectSheet.getMinDept())){
            if(Objects.isNull(deptMap.get(subjectSheet.getMinDept()))){
                rowErrs.add(ExcelLineErr.builder().line(2).msg("所属组织编码(最小)不存在").build());
            }
        }
        if(StringUtils.isNotBlank(subjectSheet.getExamType())){
            if(!subjectSheet.getExamType().matches(regex[0])){
                rowErrs.add(ExcelLineErr.builder().line(3).msg("考场类型不正确").build());
            }
        }
        return rowErrs;
    }

    public static void main(String[] args) {
        String str = "4";
        System.out.println(str.matches(regex[0]));
    }

    public static final String [] regex ={"[1-4]","[1-2]"};

    //key = deptId value = object
    private Map<String, Organization> getOfficeOrganizationMap(){
        List<Organization> officeAllDepts = iUaDeptService.getOfficeAllDepts();
        Map<String,Organization> map = officeAllDepts.stream()
                .collect(Collectors.toMap(Organization::getId, Function.identity(),(k1,k2) -> k1));
        return map;
    }

    private void excelVerify(File file) throws KqException {
        if (!file.exists()) {
            //导入文件不存在
            throw new KqException(ResponseCode.IMPORT_PLACE_ROOM_FILE_NOT_EXIST.getCode(),
                    ResponseCode.IMPORT_PLACE_ROOM_FILE_NOT_EXIST.getMsg());
        }
        String fileName = file.getName();

        if (fileName == null) {
            //导入考场信息文件类型错误
            throw new KqException(ResponseCode.PLACE_ROOM_IMPORT_FILE_TYPE_ERROR.getCode(),
                    ResponseCode.PLACE_ROOM_IMPORT_FILE_TYPE_ERROR.getMsg());
        }
        String ext = FilenameUtils.getExtension(fileName);
        if (!ext.equalsIgnoreCase(StringCodeEnum.EXCEL_XLS.getCode())
                && !ext.equalsIgnoreCase(StringCodeEnum.EXCEL_XLSX.getCode())) {
            //导入考场信息文件类型错误
            throw new KqException(ResponseCode.PLACE_ROOM_IMPORT_FILE_TYPE_ERROR.getCode(),
                    ResponseCode.PLACE_ROOM_IMPORT_FILE_TYPE_ERROR.getMsg());
        }
    }

    private void readExcel(File file, List<ImportSubjectSheet> subjectSheets) throws IOException {
        ExcelReader excelReader = EasyExcel.read(file).build();
        SubjectListener subjectListener = new SubjectListener();
        //SelfLevelListener selfLevelListener = new SelfLevelListener();
        // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener
        //ReadSheet areSheet = EasyExcel.readSheet(1).head(ImportSelfAreaSheet.class).registerReadListener(selfLevelListener).build();
        ReadSheet subjectRoomSheet = EasyExcel.readSheet(1).head(ImportSubjectSheet.class).registerReadListener(subjectListener).build();
        // 这里注意 一定要把sheet1 sheet2 一起传进去，不然有个问题就是03版的excel 会读取多次，浪费性能
        //excelReader.read(areSheet, subjectRoomSheet);
        excelReader.read(subjectRoomSheet);
        subjectSheets.addAll(subjectListener.getSubjectList());
        //areaList.addAll(selfLevelListener.getDataList());
    }

    /**
     * 分页查询
     *
     * @param pageParam
     * @param taskId
     * @param searchText
     * @return
     */
    @Override
    public Page<Subject> pageQuery(PageParam<Subject> pageParam, String taskId, String searchText){
        QueryWrapper<Subject> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(Subject::getTaskId, taskId)
                .eq(Subject::getDelFlag, false)
                .like(StringUtils.isNotBlank(searchText),Subject::getName,searchText)
                .orderByAsc(Subject::getCreateDate);
        Page<Subject> page = this.page(pageParam, queryWrapper);
        if(Objects.isNull(page) || CollectionUtils.isEmpty(page.getRecords())){
            return page;
        }
        //处理机构
        List<String> deptIds = page.getRecords().stream()
                .filter(s -> StringUtils.isNotBlank(s.getDeptId())).map(Subject::getDeptId).collect(Collectors.toList());
        Map<String, String> ancestorsNames = new HashMap<>();
        if(!CollectionUtils.isEmpty(deptIds)){
            ancestorsNames = iUaDeptService.getAncestorsNames(deptIds);
        }
        List<ExamRoomTypeVo> types = this.queryExamRoomTYpes();
        //转成map
        Map<String,ExamRoomTypeVo> typeMap = types.stream()
                .collect(Collectors.toMap(ExamRoomTypeVo::getId,Function.identity(),(k1,k2) -> k1));
        for(Subject r : page.getRecords()){
            if(Objects.nonNull(r.getDeptId())){
                r.setDeptName(ancestorsNames.get(r.getDeptId()));
            }
            if(Objects.nonNull(r.getRoomTypeId())){
                r.setRoomTypeName(Objects.nonNull(typeMap.get(r.getRoomTypeId())) ? typeMap.get(r.getRoomTypeId()).getTypeName() : "");
            }
        }
        return page;
    }

    /**
     * 查询平台科目
     * @param pageParam
     * @param param
     * @param user
     */
    @Override
    public Page<ExamSubjectDTO> queryFromPt(PageParam<Subject> pageParam, ExamSubjectParam param, User user){
        //1:先去库里查一下已经选择过了的科目
        LambdaQueryWrapper<Subject> subjectQuery = Wrappers.lambdaQuery();
        subjectQuery.eq(Subject::getTaskId,param.getTaskId()).eq(Subject::getDelFlag,Boolean.FALSE);
        List<Subject> subjects = this.baseMapper.selectList(subjectQuery);
        List<String> subjectIds = subjects.stream().map(Subject::getId).collect(Collectors.toList());
        param.setExcludeSubjectIds(subjectIds);
        ApiResponse<Page<ExamSubjectDTO>> byPage = govPtClient.getByPage(pageParam, param);
        if(Objects.isNull(byPage) || Objects.equals(ResponseCode.SUCCESS.getCode(),byPage.getCode()) ||
                Objects.isNull(byPage.getData())){
            throw new KqException(ResponseCode.SUBJECT_IMPORT_FROM_PT);
        }
        return byPage.getData();
    }

    /**
     * 查询任务绑定的科目
     * @param taskId
     * @param user
     * @return
     */
    @Override
    public List<String> queryTaskSubject(String taskId, User user){
        //1:先去库里查一下已经选择过了的科目
        LambdaQueryWrapper<Subject> subjectQuery = Wrappers.lambdaQuery();
        subjectQuery.eq(Subject::getTaskId,taskId).eq(Subject::getDelFlag,Boolean.FALSE);
        List<Subject> subjects = this.baseMapper.selectList(subjectQuery);
        List<String> subjectIds = subjects.stream().filter(e -> Objects.nonNull(e.getBmSubjectId())).map(Subject::getBmSubjectId).collect(Collectors.toList());
        return subjectIds;
    }

    public File createXml(String taskId){
        List<Subject> list = this.lambdaQuery().eq(Subject::getTaskId, taskId).eq(BaseEntity::getDelFlag, false).list();
        File file = null;
        if(CollectionUtil.isNotEmpty(list)){
            try {
                file = FileUtil.createTempFile(UUIDUtils.newSortUUID(),".xml",true);
                OedsSubject oedsSubject = new OedsSubject();
                List<ExamSubject> examSubjectList = new ArrayList<>();
                list.stream().forEach(c->{
                    ExamSubject examSubject = ExamSubject.builder().examSubjectId(c.getCode()).subjectId(c.getId())
                            .code(c.getCode()).scriptCode("1").name(c.getName()).aheadSubmitTime(c.getHandInTime().toString())
                            .remindSubmitTime(c.getRemindTime().toString()).totalTime(c.getLength().toString()).pakType("PAK1").examMode("1").build();
                    examSubjectList.add(examSubject);
                });
                oedsSubject.setExamSubjectList(examSubjectList);
                String xmlContent = XmlUtil.toXmlWithHeader(oedsSubject);
                XmlUtil.writeFile(xmlContent, file);
            } catch (Exception ex){
                if(file != null){
                   boolean flag =  file.delete();
                   if(!flag){
                       logger.error("删除考务生成汇总xml临时文件失败");
                   }
                }

                throw new KqException(ResponseCode.ERROR_CREATE_SUBJECT_XML.getCode(), "生成科目xml文件失败");
            }
        }else {
            throw new KqException(ResponseCode.NOT_EXIST_SUBJECT_DBF.getCode(), "没有编排数据，无法导出");
        }
        return file;
    }
}
